package classtoview.dao;

import classtoview.utils.StringUtils;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import classtoview.dao.BaseDAO;
import classtoview.vo.BaseVO;
import classtoview.manager.ManagerCreator;

public abstract class BaseDAO <E extends BaseVO>{
    
    @SuppressWarnings("unchecked")
    public String getNameVO(){
        return getClassVO().getSimpleName();
    }
    
    public Class getClassVO(){
        Class daoClass = this.getClass();
        Class<E> entClass = (Class<E>)((ParameterizedType)daoClass.getGenericSuperclass()).getActualTypeArguments()[0];
        return entClass;
    }
    
    public int getCount(String col, Object value){
        Query q = ManagerCreator.getInstance().createQuery("select count(e) from "+ getNameVO() +" e where e."+col+" = :val");
        q.setParameter("val", value);
        Long count = (Long)q.getSingleResult();
        if(count != null){
            return count.intValue();
        }else{
            return 0;
        }
    }
    
    public int getCount(String[] cols, Object[] values){
        Long count = (Long)getQueryWhere("select count(*) from "+ getNameVO(), cols, values).getSingleResult();
        if(count != null){
            return count.intValue();
        }else{
            return 0;
        }
    }
    
    public int getCountLike(String col, String exp) {
        Long count = (Long)ManagerCreator.getInstance().createQuery("select count(e) from "+ getNameVO() +" e where e."+col+" like '"+exp+"%'").getSingleResult();
        if(count != null){
            return count.intValue();
        }else{
            return 0;
        }
    }
    
    
    public int getCountAll(){
        Query q = ManagerCreator.getInstance().createQuery("select count(e) from "+ getNameVO()+" e");
        Long count = (Long)q.getSingleResult();
        if(count != null){
            return count.intValue();
        }else{
            return 0;
        }
    }
    
    @SuppressWarnings("unchecked")
    public List<E> getList(String sql) {
        return (List<E>)ManagerCreator.getInstance().createQuery(sql).getResultList();
    }
    
    public List<E> getListAll() {
        return (List<E>)getList("select e from "+ getNameVO()+" e");
    }
    
    public List<E> getListAllFirst(int first) {
        Query q = ManagerCreator.getInstance().createQuery("select e from "+ getNameVO()+" e");
        q.setMaxResults(first);
        return q.getResultList();
    }
    
    public List<E> getListSearch(String exp){
        List<E> list = null;
        for (Field f : getClassVO().getDeclaredFields()){
            if ((f.getType().equals(int.class) || f.getType().equals(Integer.class)) && (StringUtils.isInteger(exp))){
                if (getCount(f.getName(), Integer.parseInt(exp)) > 0){
                    list = getListEquals(f.getName(), Integer.parseInt(exp));
                    break;
                }
            }
        }
        
        if (list == null){
            for (Field f : getClassVO().getDeclaredFields()){
                try{
                    if (f.getType().equals(String.class)){
                        if (getCountLike(f.getName(), exp) > 0){
                            list = getListLike(f.getName(), exp);
                            break;
                        }
                    }
                }catch(Exception e){
                    list = null;
                }
            }
        }
        return list;
    }
    
    public List<E> getListLike(String col, String exp) {
        return (List<E>)getList("select e from "+ getNameVO() +" e where e."+col+" like '"+exp+"%'");
    }
    
    @SuppressWarnings("unchecked")
    public List<E> getListEquals(String col, Object val) {
        Query q = ManagerCreator.getInstance().createQuery("select e from "+ getNameVO() +" e where e."+col+" = :val");
        q.setParameter("val", val);
        return (List<E>)q.getResultList();
    }
    
    protected Query getQueryWhere(String sql, String[] cols, Object[] values){
        sql += " where ";
        String sep = "";
        for (String col : cols){
            sql += sep + col +"=:"+ col;
            sep = " and ";
        }
        Query q = ManagerCreator.getInstance().createQuery(sql);
        for (int i=0;i<cols.length;i++){
            q.setParameter(cols[i], values[i]);
        }
        return q;
    }
    
    @SuppressWarnings("unchecked")
    public List<E> getListEquals(String[] cols, Object[] values) {
        return (List<E>)getQueryWhere("from "+ getNameVO(), cols, values).getResultList();
    }
    
    public void insert(E bean) {
        ManagerCreator.getInstance().getTransaction().begin();
        ManagerCreator.getInstance().persist(bean);
        ManagerCreator.getInstance().getTransaction().commit();
    }
    
    public void update(E bean) {
        BaseVO ent = (BaseVO)ManagerCreator.getInstance().find(bean.getClass(), bean.getIdValue());
        ent.popule(bean);
        ManagerCreator.getInstance().getTransaction().begin();
        ManagerCreator.getInstance().merge(ent);
        ManagerCreator.getInstance().getTransaction().commit();
    }
    public boolean exist(E bean){
        BaseVO ent = (BaseVO)ManagerCreator.getInstance().find(bean.getClass(), bean.getIdValue());
        return ent != null;
    }
    
    public void delete(E bean) {
        Object ent = ManagerCreator.getInstance().find(bean.getClass(), bean.getIdValue());
        ManagerCreator.getInstance().getTransaction().begin();
        ManagerCreator.getInstance().remove(ent);
        ManagerCreator.getInstance().getTransaction().commit();
    }
}
